﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using mojoPortal.Web;
using blackhouse.BlackApart.Business.Apartments;
using blackhouse.BlackApart.Business;
using blackhouse.BlackApart.Web;
using System.Globalization;
using blackhouse.Web;
using blackhouse.BlackApart.Business.Reservations;
using blackhouse.BlackApart.Business.Prices;
using blackhouse.BlackApart.Business.Opinions;
using blackhouse.JavaScript.JQuery;
using System.IO;
using blackhouse.BlackApart.Web.Modules;

namespace blackhouse.Aparts.Web.Pages {
	public partial class Reservation : NonCmsBasePage {

		#region Fields

		private DateTime arrivalDate = DateTime.Now;
		private DateTime departureDate = DateTime.Now.AddDays(1);
		private int maxPeopleCount = 12;
		private int peopleCount = 1;
		private int apartmentType = 0;

		private IApartmentGroup[] allApartmentTypes;
		private Factory factory = Factory.Instance();

		private bool isValid = true;

		private Variant[] variants;
		private SearchReservationPerRequest reservationSaver;

		private bool showApartmentTypeWarning = false;
		private bool showNoFreeApartmentsWarning = false;

		#endregion

		#region Event Handlers

		protected override void OnPreInit(EventArgs e) {
			this.AllowSkinOverride = true;
			HttpContext.Current.Items.Add("skin", "blackhouse");

			base.OnPreInit(e);
		}

		protected override void OnInit(EventArgs e) {
			base.OnInit(e);

			if (this.IsPostBack && Request.Form["action"] == "navigateToSearch") {
				this.ReadPostbackParameters();
				this.Response.Redirect(UrlUtils.GetReservationUrl(factory.GetPreFolderEvaluation(), this.arrivalDate, this.departureDate, this.peopleCount, this.apartmentType), true);
			}
			this.ReadInputParameters();
			this.CheckValid();
			this.SetInstance();

			this.rptVariants.ItemDataBound += new RepeaterItemEventHandler(ItemDataBoundRptVariants);
		}

		protected override void OnLoad(EventArgs e) {
			base.OnLoad(e);

			this.PopulateControls();
			this.AddJavaScripts();
			this.SetPageSeo();
		}

		#endregion

		#region Methods

		private void AddJavaScripts() {
			JQueryLibraries jql = new JQueryLibraries();
			jql.IncludeJQueryFancybox();
			jql.IncludeJQueryUICulture(CultureInfo.CurrentCulture);
			jql.IncludeFileBasedOnJQuery("blackhouse.Aparts.Web.Scripts.reservation.js,blackhouse.Aparts.Web");
		}

		private void CheckValid() {
			if (!this.DatesIsValid()) {
				this.PopulateErrorMessage(GetGlobalResourceObject("Aparts", "searchApartmentsIncorectDates").ToString(), false);
				this.isValid = false;
			}
			if (this.peopleCount < 1 || this.peopleCount > this.maxPeopleCount) {
				this.PopulateErrorMessage(GetGlobalResourceObject("Aparts", "searchApartmentsIncorectDates") + " 1 - " + this.maxPeopleCount + "!", false);
				this.isValid = false;
			}
			if (this.apartmentType > 0) {
				IApartmentGroup type = factory.GetApartmentGroup(this.apartmentType);
				if (type == null || type.Id != this.apartmentType) {
					this.PopulateErrorMessage(GetGlobalResourceObject("Aparts", "searchApartmentsIncorectDates").ToString(), false);
					this.isValid = false;
				}
			}
		}

		private bool DatesIsValid() {
			return this.arrivalDate.Date >= DateTime.Now.Date
				&& this.departureDate.Date > this.arrivalDate.Date;
		}

		private void PopulateErrorMessage(string message, bool endResponse) {
			this.pnlErrorHolder.Controls.Add(new Label() { Text = message + "<br />" });
			this.pnlErrorHolder.Visible = true;
			if (endResponse)
				Response.End();
		}

		private void ReadInputParameters() {
			if (!Int32.TryParse(this.Request[UrlUtils.ParameterApartmentTypeId], out this.apartmentType)) this.apartmentType = 0;
			if (!Int32.TryParse(this.Request[UrlUtils.ParameterPersons], out this.peopleCount)) this.peopleCount = 1;
			this.arrivalDate = this.ReadDateInputParameter(UrlUtils.ParameterArrival, this.arrivalDate);
			this.departureDate = this.ReadDateInputParameter(UrlUtils.ParameterDeparture, this.departureDate);
		}

		private DateTime ReadDateInputParameter(string parameterName, DateTime fallback) {
			DateTime date;
			if (DateTime.TryParseExact(this.Request[parameterName], "yyyyMMdd", CultureInfo.CurrentCulture, DateTimeStyles.None, out date))
				return date;
			else
				return fallback;
		}

		private void ReadPostbackParameters() {
			this.arrivalDate = this.ReadPostbackDate(this.ddlDay1, this.ddlMonth1, this.ddlYear1, this.arrivalDate);
			this.departureDate = this.ReadPostbackDate(this.ddlDay2, this.ddlMonth2, this.ddlYear2, this.departureDate);
			if (!Int32.TryParse(this.Request.Form[this.ddlPeopleCount.UniqueID], out this.peopleCount)) peopleCount = 1;
			if (!Int32.TryParse(this.Request.Form[this.ddlApartmentType.UniqueID], out this.apartmentType)) apartmentType = 0;
		}

		private DateTime ReadPostbackDate(DropDownList ddlDay, DropDownList ddlMonth, DropDownList ddlYear, DateTime fallbackDate) {
			string sDay, sMonth, sYear;
			sDay = this.Request.Form[ddlDay.UniqueID];
			sMonth = this.Request.Form[ddlMonth.UniqueID];
			sYear = this.Request.Form[ddlYear.UniqueID];

			if (string.IsNullOrEmpty(sDay)
				|| string.IsNullOrEmpty(sMonth)
				|| string.IsNullOrEmpty(sYear))
				return fallbackDate;

			int day, month, year;

			if (!(
				Int32.TryParse(sDay, out day)
				&& Int32.TryParse(sMonth, out month)
				&& Int32.TryParse(sYear, out year)
				)) return fallbackDate;

			try {
				DateTime date;
				date = new DateTime(year, month, day);
				return date;
			}
			catch {
				return fallbackDate;
			}

		}

		private void SetInstance() {
			this.allApartmentTypes = factory.GetApartmentGroup().GetAllApartmentTypes();
			this.SetSearchVariants();
			this.showNoFreeApartmentsWarning = this.variants.Length == 0;
		}

		private void SetSearchVariants() {
			if (this.isValid) {
				IUserReservation findReservation = this.factory.CreateUserReservation();
				findReservation.SetDates(this.arrivalDate, this.departureDate);
				findReservation.SetForPeoples(this.peopleCount);
				if (this.apartmentType > 0 && findReservation is ConfiguredUserReservation) {
					(findReservation as ConfiguredUserReservation).SetGroupFilter(this.apartmentType);
				}
				this.variants = findReservation.Find();
				if (this.variants.Length == 0 && this.apartmentType > 0) {
					this.showApartmentTypeWarning = true;
					this.apartmentType = 0;
					this.SetSearchVariants();
					return;
				}
			}
			else this.variants = new Variant[0];
		}

		private void SetPageSeo() {
			PageProvider seo = PageProvider.Instance();
			seo.SetPageTitle(GetGlobalResourceObject("Aparts", "reservationPageTitle").ToString());
			seo.SetPageKeywords(GetGlobalResourceObject("Aparts", "reservationKeywords").ToString());
			seo.SetPageDescription(GetGlobalResourceObject("Aparts", "reservationDescription").ToString());
			seo.SetCanonicalUrl(UrlUtils.GetReservationUrl(factory.GetPreFolderEvaluation(), this.arrivalDate, this.departureDate, this.peopleCount, this.apartmentType));
		}

		private void PopulateControls() {
			this.BindDayDropDownList(this.ddlDay1, this.arrivalDate);
			this.BindDayDropDownList(this.ddlDay2, this.departureDate);
			this.BindMonthDropDownList(this.ddlMonth1, this.arrivalDate);
			this.BindMonthDropDownList(this.ddlMonth2, this.departureDate);
			this.BindYearDropDownList(this.ddlYear1, this.arrivalDate);
			this.BindYearDropDownList(this.ddlYear2, this.departureDate);
			this.BindPeopleCountDropDownList(this.ddlPeopleCount, this.maxPeopleCount, this.peopleCount);
			this.BindApartmentTypesDropDownList(this.ddlApartmentType, this.allApartmentTypes, this.apartmentType);
			if (this.showNoFreeApartmentsWarning)
				this.pnlNoFreeApartmentsWarning.Visible = true;
			if (this.showApartmentTypeWarning && !this.showNoFreeApartmentsWarning)
				this.pnlApartmentTypeWarning.Visible = true;

			this.PopulateVariants();
		}

		private void PopulateVariants() {
			this.reservationSaver = new SearchReservationPerRequest(this.arrivalDate, this.departureDate, this.peopleCount);
			for (int xv = 0; xv < this.variants.Length; xv++)
				this.reservationSaver.AddVariant(this.variants[xv]);
			this.reservationSaver.Save(new DirectoryInfo(Server.MapPath("/SavedReservations")));

			var orderedByPrice = this.variants.OrderBy(v => v.Price.GetPrice());
			this.rptVariants.DataSource = orderedByPrice;
			this.rptVariants.DataBind();
		}

		private void ItemDataBoundRptVariants(object sender, RepeaterItemEventArgs e) {
			switch (e.Item.ItemType) {
				case ListItemType.AlternatingItem:
				case ListItemType.Item:
					this.ItemDataBoundRptVariantsAction(sender, e);
					break;
				default:
					break;
			}
		}

		private void ItemDataBoundRptVariantsAction(object sender, RepeaterItemEventArgs e) {
			Variant variant = e.Item.DataItem as Variant;
			if (variant != null) {
				Image imgApartment = e.Item.FindControl("imgApartment") as Image;
				Literal lblApartmentName = e.Item.FindControl("lblApartmentName") as Literal;
				Literal lblApartmentDesription = e.Item.FindControl("lblApartmentDesription") as Literal;
				CurrencyLiteral lblPrice1 = e.Item.FindControl("lblPrice1") as CurrencyLiteral;
				CurrencyLiteral lblPrice2 = e.Item.FindControl("lblPrice2") as CurrencyLiteral;
				CurrencyLiteral lblPrice3 = e.Item.FindControl("lblPrice3") as CurrencyLiteral;
				Literal lblRanking = e.Item.FindControl("lblRanking") as Literal;
				HyperLink lnkShowDescription = e.Item.FindControl("lnkShowDescription") as HyperLink;
				HyperLink lnkMakeReservation = e.Item.FindControl("lnkMakeReservation") as HyperLink;
				Panel pnlMoreOne = e.Item.FindControl("pnlMoreOne") as Panel;

				// wyświetla tylko propozycje rezerwacji na jeden typ apartamentu
				if (variant.AreVariousApartmentTypes || variant.ItIsChangeInLocation) {
					e.Item.Visible = false;
					return;
				}

				IApartmentGroup group = variant.GetGroups().FirstOrDefault();
				if (imgApartment != null) {
					IApartmentPhoto[] photos = factory.GetApartmentPhoto().GetApartmentTypePhotos(group.Id);
					IApartmentPhoto photo = photos.OrderBy(p => p.Sort).ThenBy(p => p.PhotoName).FirstOrDefault();
					if (photo != null)
						ImageUtils.ApartmentPhotoReservationImage(imgApartment, photo);
				}
				if (lblApartmentName != null)
					lblApartmentName.Text = group.Name;
				if (lblApartmentDesription != null)
					lblApartmentDesription.Text = group.GetProperty("opis").ToString().SubstringToWord(250);

				// CENY
				int lengthOfStay = (int)Math.Ceiling((this.departureDate - this.arrivalDate).TotalDays);

				if (lblPrice1 != null)
					lblPrice1.Value = variant.Price.GetPrice() / this.peopleCount / lengthOfStay;

				if (lblPrice2 != null)
					lblPrice2.Value = variant.Price.GetPrice() / lengthOfStay;

				if (lblPrice3 != null)
					lblPrice3.Value = variant.Price.GetPrice();

				if (lblRanking != null) {
					StatisticsOpinion opinion = factory.GetStatisticsOpinion();
					opinion.SetFilterByApartmentType(group.Id);
					lblRanking.Text = opinion.GetAverageRatingAsText();
				}
				if (lnkShowDescription != null) {
					lnkShowDescription.NavigateUrl = UrlUtils.GetApartmentTypeUrl(factory.GetPreFolderEvaluation(), group, DisplayApartmentTypeView.Default, 1);//UrlUtils.LocalizeUrl(factory.GetPreFolderEvaluation(), string.Format("/Pages/DisplayApartmentPopup.aspx?apartmentType={0}&forceurl=1&skin=blackhouse-popup", group.Id));
				}
				if (lnkMakeReservation != null)
					lnkMakeReservation.NavigateUrl = UrlUtils.LocalizeUrl(factory.GetPreFolderEvaluation(), string.Format("/Pages/ProgressReservation.aspx?reservation={0}&variant={1}", this.reservationSaver.Id, this.reservationSaver.GetIdForVariant(variant)));

				if (variant.ApartmentCount > 1 && pnlMoreOne != null) {
					Literal lblApartCount = pnlMoreOne.FindControl("lblApartCount") as Literal;
					Literal lblApartPeopleCount = pnlMoreOne.FindControl("lblApartPeopleCount") as Literal;
					if (lblApartCount != null && lblApartPeopleCount != null) {
						pnlMoreOne.Visible = true;
						lblApartCount.Text = variant.ApartmentCount.ToString();
						lblApartPeopleCount.Text = variant.Items[0].Apartment.NumberOfPeople.ToString();
					}
				}
			}
		}

		private void BindApartmentTypesDropDownList(DropDownList ddl, IApartmentGroup[] groups, int currentValue) {
			ddl.Items.Clear();
			ddl.Items.Add(new ListItem(GetGlobalResourceObject("Aparts", "any").ToString(), "0"));
			foreach (IApartmentGroup group in groups) {
				ListItem li = new ListItem(group.Name, group.Id.ToString());
				li.Selected = group.Id == currentValue;
				ddl.Items.Add(li);
			}
		}

		private void BindPeopleCountDropDownList(DropDownList ddl, int maxPeoples, int currentValue) {
			ddl.Items.Clear();
			for (int i = 1; i <= maxPeoples; i++) {
				ListItem li = new ListItem(i.ToString(), i.ToString());
				li.Selected = i == currentValue;
				ddl.Items.Add(li);
			}
		}

		private void BindDayDropDownList(DropDownList ddl, DateTime currentDate) {
			ddl.Items.Clear();
			currentDate = currentDate.AddMonths(1);
			int maxDay = new DateTime(currentDate.Year, currentDate.Month, 1).AddDays(-1).Day;
			for (int i = 1; i <= 31; i++) {
				ListItem li = new ListItem(i.ToString("D2"), i.ToString());
				li.Selected = currentDate.Day == i;
				if (i > maxDay) li.Attributes.Add("style", "display:none");
				ddl.Items.Add(li);
			}
		}

		private void BindMonthDropDownList(DropDownList ddl, DateTime currentDate) {
			ddl.Items.Clear();
			for (int i = 1; i <= 12; i++) {
				DateTime dt = new DateTime(currentDate.Year, i, 1);
				ListItem li = new ListItem(dt.ToString("MMMM"), i.ToString());
				li.Selected = currentDate.Month == i;
				li.Attributes.Add("m-d", dt.AddMonths(1).AddDays(-1).Day.ToString());
				ddl.Items.Add(li);
			}
		}

		private void BindYearDropDownList(DropDownList ddl, DateTime currentDate) {
			ddl.Items.Clear();
			ListItem li = new ListItem(DateTime.Now.Year.ToString(), DateTime.Now.Year.ToString());
			li.Selected = currentDate.Year == DateTime.Now.Year;
			ddl.Items.Add(li);
			li = new ListItem(DateTime.Now.AddYears(1).Year.ToString(), DateTime.Now.AddYears(1).Year.ToString());
			li.Selected = currentDate.Year == DateTime.Now.AddYears(1).Year;
			ddl.Items.Add(li);
		}

		#endregion

	}
}